#include <iostream>

#include <string.h>
#include <iostream>
using namespace std;

class CowString
{
public:
	CowString()
	: _pstr(new char[1 + refCountCapacity]() + refCountCapacity)
	{
		//对引用计数进行初始化
		initRefcount();
	}

	CowString(const char * pstr)
	: _pstr(new char[strlen(pstr) + refCountCapacity + 1]() + refCountCapacity)
	{
		strcpy(_pstr, pstr);
		initRefcount();//初始化引用计数
	}

	CowString(const CowString & rhs)
	: _pstr(rhs._pstr) //浅拷贝
	{
		increaseRefcount();	//引用技术加1
	}

	CowString & operator=(const CowString & rhs)
	{
		if(this != &rhs) {//1. 自复制
			//2. 回收左操作数的空间
			release();

			//3. 进行浅拷贝
			_pstr = rhs._pstr;
			increaseRefcount();//引用技术加1
		}
		return *this;//4. return *this
	}

	void release() {
		decreaseRefcount();
		if(refCount() == 0) {
			delete [] (_pstr - refCountCapacity);
			cout << " >> delete heap data" << endl;
		}
	}

	~CowString()
	{
		release();
	}

	//问题: 下标访问运算符无法区分出接下来要做的是读操作还是写操作
	char & operator[](int idx)
	{
		if(idx >=0 && idx < length()) {
			if(refCount() > 1) {
				//当引用计数的值大于1时，要进行深拷贝
				char * ptmp = new char[length() + 1 + refCountCapacity]() + refCountCapacity;
				strcpy(ptmp, _pstr);
				decreaseRefcount();//将原来字符串的引用计数减1
				_pstr = ptmp;//指向新的空间
				initRefcount();//对新空间的字符串引用计数进行初始化
			}
			return _pstr[idx];
		} else {
			static char nullchar = '\0';
			return nullchar;
		}
	}

	int length() const {	return strlen(_pstr);	}

	const char * c_str() const
	{	return _pstr;	}

	int refCount() const
	{
		return *reinterpret_cast<int*>(_pstr - refCountCapacity);
	}

	friend std::ostream & operator<<(std::ostream & os, const CowString&rhs);
private:
	void initRefcount()
	{
		*reinterpret_cast<int*>(_pstr - refCountCapacity) = 1;
	}

	void increaseRefcount()
	{
		++*reinterpret_cast<int*>(_pstr - refCountCapacity);
	}
	
	void decreaseRefcount()
	{
		--*reinterpret_cast<int*>(_pstr - refCountCapacity);
	}
private:
	//_pstr永远指向的是字符串内容的首地址
	char * _pstr;
	static const int refCountCapacity = 4;
};
 
std::ostream & operator<<(std::ostream & os, const CowString & rhs)
{
	os << rhs._pstr;
	return os;
}


int main()
{
    CowString str1 = "hello, world!";
    cout << "str1:" << str1 << endl;
    cout << "str1's refcount: " << str1.refCount() << endl;
    printf("str1's content address: %p\n\n", str1.c_str());

    CowString str2 = str1; // 此时 str2 与 str1 共享底层字符数组
    cout << "执行拷贝构造CowString str2 = str1 之后:" << endl;
    cout << "str1:" << str1 << endl;
    cout << "str1's refcount: " << str1.refCount() << endl;
    printf("str1's content address: %p\n\n", str1.c_str());
    cout << "str2:" << str2 << endl;
    cout << "str2's refcount: " << str2.refCount() << endl;
    printf("str2's content address: %p\n\n", str2.c_str());

    str1[0] = 'H'; // str1 进行写入操作，触发复制

    cout << "执行str1[0] = 'H' 之后: " << endl;
    cout << "str1:" << str1 << endl;
    cout << "str1's refcount: " << str1.refCount() << endl;
    printf("str1's content address: %p\n\n", str1.c_str());
    cout << "str2:" << str2 << endl;
    cout << "str2's refcount: " << str2.refCount() << endl;
    printf("str2's content address: %p\n\n", str2.c_str());
    return 0;
}

